package pokerAI.PokerAI;
import java.util.HashMap;
import java.util.LinkedList;

public class AIPlayer extends Player{
        private GameState g;    
        private HandEvaluator handEval;
        private HandCompTest handCompT;
        private LinkedList<Action> oppActionLog;
        private HashMap<Player, Integer> oppStrength;
        private HashMap<Player, Integer> oppHandStrength;
        private double myHandStrength;
        private boolean beWary;
		
        
        public AIPlayer(GameState gState, int pNum)
        {
                super("Default AI name", pNum );
                g = gState;
                this.setType("AI");
                handEval = new HandEvaluator();
                handCompT = new HandCompTest();
                oppStrength = new HashMap<Player,Integer>();
                oppHandStrength = new HashMap<Player,Integer>();                
                beWary = false;
        }
        public AIPlayer(String n, int pNum, GameState gState)
        {
                super(n, pNum);
                this.setType("AI");
                g = gState;
                oppStrength = new HashMap<Player,Integer>();
                oppHandStrength = new HashMap<Player,Integer>();
                handEval = new HandEvaluator();
                handCompT = new HandCompTest();
        }
        public String act(String[] validActions, int lastCurrBet)
        {
                System.out.println("" + this.getName() + " is thinking...");
                oppActionLog = g.getActionLog();
                updateOppInfo();
                myHandStrength = calcHandStrength();
                g.clearActionLog();
                hasActed=true;
                return decide(validActions, lastCurrBet);
        }
        public void init()
        {
                LinkedList<Player> temp = g.getPlayers();
                for(int i=0; i<temp.size(); i++)
                {
                        oppStrength.put(temp.get(i), 0);
                        oppHandStrength.put(temp.get(i), 0);
                }
        }
        private void updateOppInfo()
        {
                if(oppActionLog.size() != 0)
                {
                        for(int i=0; i<oppActionLog.size(); i++)
                        {
                                Action oppAction = oppActionLog.get(i);
                                int prevStrength = oppHandStrength.get(oppAction.getPlayer());
                                if(oppAction.getAction().equals("bet"))
                                {                               
                                        oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/10));
                                }
                                else if(oppActionLog.get(i).equals("raise"))
                                {                               
                                        oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/5));
                                }
                                else if(oppActionLog.get(i).equals("call"))
                                {
                                        oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/12));
                                }
                                else if(oppActionLog.get(i).equals("check"))
                                {
                                        oppHandStrength.put(oppAction.getPlayer(), prevStrength - (oppAction.getAmount()/20));
                                }
                                else
                                {
                                        oppHandStrength.put(oppAction.getPlayer(), 0);
                                }
                        }
                }
        }
        public void resetRound()
        {
                LinkedList<Player> temp = g.getPlayers();
                for(int i=0; i<temp.size(); i++)
                {
                        oppHandStrength.put(temp.get(i), 0);
                }
        }
        private String decide(String[] validActions, int lastCurrBet)
        {
                if(validActions[0] == "bet")
                {
                        boolean toBet = false;
                        if(myHandStrength*2/g.getNumPlayers() > 50.0*2/g.getNumPlayers())
                        {
                                toBet = true;
                                if(shouldBeWary())
                                {
                                        calcBet(1);                                     
                                }
                                else
                                {
                                        calcBet(0);
                                }
                        }
                        if(toBet)
                                return "bet";
                        else
                                return "check";
                }
                else
                {
                        boolean toRaise = false;
                        boolean toCall = false;
                        if(myHandStrength*2/g.getNumPlayers() > 70.0*2/g.getNumPlayers())
                        {
                                toRaise = true;
                                if(shouldBeWary())
                                {
                                        calcBet(1);                                     
                                }
                                else
                                {
                                        calcBet(0);
                                }
                        }
                        else if(myHandStrength*2/g.getNumPlayers() > 50.0*2/g.getNumPlayers())
                        {
                                toCall = true;                          
                        }
                        if(toRaise)
                                return "raise";
                        else if(toCall)
                        {
                                setBet(lastCurrBet);
                                return "call";
                        }
                        else
                                return "fold";
                }
        }
        public void playerWon(Player p)
        {
                int prevVal = oppStrength.get(p);
                oppStrength.put(p, (int)(prevVal+(Math.random()*5)));
        }
        private void calcBet(int mode) //0 for normal, 1 for wary, 2 for slowplay
        {
                if(mode == 0)
                {
                        if(g.getPot() == 0)
                        {
                                if(myHandStrength > 50.0)
                                {
                                        this.setBet((int)(10*(myHandStrength-50)));
                                }
                        }
                        else
                        {
                                if(myHandStrength > 50.0)
                                {
                                        this.setBet((int)(10*(myHandStrength-50)));
                                }
                        }
                }
        }
        private boolean shouldBeWary()
        {
                return beWary;
        }
        private void checkWary()
        {
                LinkedList<Player> p = g.getPlayers();
                for(int i=0; i<p.size();i++)
                {
                        if(oppHandStrength.get(p.get(i)) > 50)
                        {
                                beWary = true;
                        }
                }
        }
        private double calcHandStrength()
        {
                if(g.getCurrRound() == 0)
                {
                        return handEval.preFlopHandRank(this.getHoleCards());
                }
                else{
                        /// load an array with the community cards and players (2) cards
                        int sizeOfCommCardz = g.getCommCards().size();
                        Card[] cardz = new Card[sizeOfCommCardz + 2];
                        int i=0;
                        // loading community cards
                        for(i = 0; i < sizeOfCommCardz; i++){
                                cardz[i] = g.getCommCards().get(i);
                        }
                        // loading players two cards
                        cardz[i] = this.getHoleCards().get(0);
                        i++;
                        cardz[i] = this.getHoleCards().get(1);
                        
                        /// pass it to the handcomptester
                        double rvalue = handCompT.handComp(cardz);
                        rvalue = ((rvalue /2099)* 100 );
                        return rvalue;
                }       
        }
        public void printOppInfo()
        {
                System.out.println();
                System.out.println("--- " + this.getName() + " ---");
                System.out.println("Perceived Player Strength");
                LinkedList<Player> temp = g.getPlayers();
                for(int i=0; i<oppStrength.size(); i++)
                {
                        System.out.println("     " + temp.get(i).getName() + " - " + oppStrength.get(temp.get(i)));
                }
                
        }

}
